package org.redmagic.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import org.mockito.Mockito;
import org.redmagic.Request;
import org.redmagic.service.utils.MongoProperties;
import org.redmagic.service.utils.MongoUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;

public abstract class AbstractMongoDbBackedTestCase {

	protected static final String USER_PROPERTY = "database/user";
	protected static final String PASSWORD_PROPERTY= "database/password";
	protected static final String HOST_PROPERTY = "database/host";
	protected static final String HOSTNAME_PROPERTY = "hostname";
	protected static final String DOMAIN_PROPERTY = "domain";
	
	protected static final String SYSTEM_TYPE_TAG = "systemType=production";
	protected static final String RELEASE_TAG = "release=1.0";
	protected static final String LOCALHOST_TAG = "localhost";
	
	protected static final String USER_VALUE = "test_user";
	
	protected static final List<String> LOCAL_RELEASE_SYSTEM_TAGS = Lists.newArrayList(SYSTEM_TYPE_TAG, LOCALHOST_TAG, RELEASE_TAG);
	protected static final List<String> RELEASE_SYSTEM_TAGS = Lists.newArrayList(SYSTEM_TYPE_TAG, RELEASE_TAG);
	protected static final List<String> RELEASE_TAGS = Lists.newArrayList(RELEASE_TAG);
	protected static final List<String> NO_TAGS = Lists.newArrayList();
	
	@Rule
	public ExpectedException expectedException = ExpectedException.none();
	
	protected Mongo mongo;
	protected DB db;
	protected DBCollection collection;
	protected DBObject fields;
	
	@Before
	public void setUp() {
		
		this.mongo = Mockito.mock(Mongo.class);
		this.db = Mockito.mock(DB.class);
		this.collection = Mockito.mock(DBCollection.class);
		
		Mockito.when(mongo.getDB("test")).thenReturn(db);
		Mockito.when(db.getCollection("test")).thenReturn(collection);
		
		this.fields = new BasicDBObject(MongoProperties.ID, 0);
		this.fields.put(MongoProperties.VALUE_KEY, 1);
	}
	
	@After
	public void tearDown() {
		
		this.collection = null;
		this.db = null;
		this.mongo = null;
	}
	
	protected void mockQuery(String base, List<String> tags, String value) {
		DBObject query = MongoUtils.getQuery(base, tags);
		Mockito.when(collection.findOne(query, fields)).thenReturn(new BasicDBObject(MongoProperties.VALUE_KEY, value));
	}
	
	@SuppressWarnings("unchecked")
	protected Request getFullRequest() {
		List<List<String>> hierarchy = Lists.newArrayList(LOCAL_RELEASE_SYSTEM_TAGS, RELEASE_SYSTEM_TAGS, RELEASE_TAGS);
		Set<String> placeholders = Sets.newHashSet(USER_PROPERTY, PASSWORD_PROPERTY, HOST_PROPERTY);
		
		return new TestRedMagicRequest(hierarchy, placeholders);
	}
	
	protected Request getPartialRequest() {
		List<List<String>> hierarchy = new ArrayList<List<String>>();
		hierarchy.add(RELEASE_TAGS);
		Set<String> placeholders = Sets.newHashSet(HOST_PROPERTY);
		
		return new TestRedMagicRequest(hierarchy, placeholders);
	}
	
	private class TestRedMagicRequest implements Request {

		private final List<List<String>> hierarchy;
		private final Set<String> placeholders;
		
		public TestRedMagicRequest(List<List<String>> hierarchy, Set<String> placeholders) {
			this.hierarchy = hierarchy;
			this.placeholders = placeholders;
		}
		
		@Override
		public List<List<String>> getHierarchy() {
			return hierarchy;
		}

		@Override
		public Set<String> getPlaceholders() {
			return placeholders;
		}

		@Override
		public String marshall() {
			throw new RuntimeException("Not implemented in test request");
		}

		@Override
		public String getMediaType() {
			// TODO Auto-generated method stub
			return null;
		}
		
	}
}
